1. 입력 데이터 구조
- 각 행(row)은
(user_id, movie_title)
쌍으로 구성됩니다.
예: [user_123, "인셉션"]
→ 사용자 123이 "인셉션"을 시청했다는 기록.
2. 라벨 생성 방식
- Positive Label:
데이터셋에 명시된 (user_id, movie_title)
쌍은 자동으로 positive로 간주됩니다.
→ "사용자가 이 영화를 좋아한다"고 가정합니다.
- Negative Label:
같은 배치(batch) 내 다른 영화들은 암시적 negative로 처리됩니다.
→ "사용자가 이 영화를 시청하지 않았다"고 추정합니다.
3. 실제 동작 예시
배치 데이터 예시
batch = [
{"user_id": "user_A", "movie_title": "인셉션"},
{"user_id": "user_B", "movie_title": "테넷"},
{"user_id": "user_C", "movie_title": "다크나이트"}
]
학습 시 Negative 샘플링
- user_A의 관점:
- Positive: "인셉션"
- Negatives: "테넷", "다크나이트" (배치 내 다른 영화)
- user_B의 관점:
- Positive: "테넷"
- Negatives: "인셉션", "다크나이트"
4. 손실 계산 로직
5. 주의점
- 암시적 부정 샘플의 한계:
사용자가 실제로 좋아할 수 있지만 아직 시청하지 않은 영화가 negative로 잘못 처리될 수 있습니다.
→ 모델은 "시청한 것 vs. 시청하지 않은 것"을 구분하도록 학습되지만, 완벽하지는 않습니다.
- 해결 방안:
- 명시적 negative 데이터가 있다면 별도로 추가합니다.
- 하이퍼파라미터 조정: 배치 크기, negative 샘플 수 등을 실험적으로 최적화합니다.
6. 코드 수준의 동작
- TFRS의
Retrieval
Task: task = tfrs.tasks.Retrieval(
metrics=...,
)
- 직접 구현한 모델(
NoBaseClassMovielensModel
): def train_step(self, features):
positive_movie = self.movie_model(features["movie_title"])
loss = self.task(user_embedding, positive_movie)